<?php

namespace App\Kuafu\Shop\Service;

use App\Kuafu\Base\Enum\BaseCodeEnum;
use App\Kuafu\Base\Service\BaseService;
use App\Kuafu\Config\Model\ConfigModel;
use App\Kuafu\Customer\Exceptions\CustomerException;
use App\Kuafu\Nsq\Enum\NsqCodeEnum;
use App\Kuafu\Shop\Enum\CodeEnum;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\Shop\Model\ShopUnifiedManagementModel;
use App\Kuafu\User\Model\User;
use Carbon\Carbon;
use Kuafu\File\FileUtil;
use Kuafu\Nsq\NsqPublisher;
use PhpOffice\PhpSpreadsheet\IOFactory;

class UnifiedManagementService extends BaseService
{
    public static function index(int $type, array $shopIds = [], int $pageNum = 1, int $pageSize = 10)
    {
        $paginator = ShopUnifiedManagementModel::query()
            ->where('type', $type)
            ->when(count($shopIds), function ($q) use ($shopIds) {
                $q->whereIn('shopId', $shopIds);
            })
            ->with(['shop'])
            ->orderBy('shopId', 'desc')
            ->paginate($pageSize, ['*'], 'pageNum', $pageNum);
        return static::pageLists($paginator, function (ShopUnifiedManagementModel $m) {
            return [
                'id'            => $m->id,
                'shopId'        => $m->shopId,
                'shopCode'      => (string)optional($m->shop)->shopCode,
                'name'          => (string)optional($m->shop)->name,
                'addressPrefix' => (string)optional($m->shop)->addressPrefix,
            ];
        });
    }

    public static function notify(int $type, int $uid, string $username)
    {
        $shopIds = ShopUnifiedManagementModel::query()
            ->where('type', $type)
            ->pluck('shopId')
            ->toArray();
        (new NsqPublisher(config('nsq.default.address')))
            ->pub(NsqCodeEnum::SHOP_UNIFIED_MANAGEMENT_CHANGED, [
                'type'     => $type,
                'shopIds'  => array_values(array_unique($shopIds)),
                'uid'      => $uid,
                'username' => $username,
            ]);
    }

    protected static function importShopCodes(string $filepath): array
    {
        try {
            $spreadsheet = IOFactory::load($filepath);
        } catch (\Exception $exception) {
            throw new CustomerException(BaseCodeEnum::ERR_INVALID_FILE, '读取excel文件内容失败');
        }
        $sheet      = $spreadsheet->getActiveSheet();
        $shopCodes  = [];
        $highestRow = $sheet->getHighestRow('A');
        for ($row = 2; $row <= $highestRow; $row++) {
            $code = (int)trim($sheet->getCell("A{$row}")->getCalculatedValue());
            if ($code < 1) {
                continue;
            }
            $shopCodes[$code] = $code;
        }
        return $shopCodes;
    }

    public static function waimaiImport(string $filepath, array $blackShopIds, ?User $operator = null)
    {
        if (count($blackShopIds)) {
            // 存黑名单
            static::syncAll($blackShopIds, $operator, ShopUnifiedManagementModel::TYPE_WAIMAI_BLACK);
            // 刷新白名单
            static::waimaiRefreshWhite($operator);
            // 触发NSQ消息
            static::notify(ShopUnifiedManagementModel::TYPE_WAIMAI_WHITE, (int)optional($operator)->id, $operator ? $operator->username : '系统自动处理');
            // 记录日志
            static::addHistory(ShopUnifiedManagementModel::TYPE_WAIMAI_BLACK, $blackShopIds, $operator);
            return [];
        }
        // 外卖导入的是黑名单，没过滤的
        $blackShopCodesBefore = static::importShopCodes($filepath);
        // 外卖导入的是黑名单，过滤的
        $blackShops = static::shopCodesToShops($blackShopCodesBefore);
        return collect($blackShops)->map(function ($item) {
            return collect($item)->only(['id', 'shopCode', 'name'])->toArray();
        })->values()->toArray();
    }

    public static function douyinImport(string $filepath, array $shopIds, ?User $operator)
    {
        if (count($shopIds)) {
            // 存白名单
            static::syncAll($shopIds, $operator, ShopUnifiedManagementModel::TYPE_DOUYIN_WHITE);
            // 推NSQ消息
            static::notify(ShopUnifiedManagementModel::TYPE_DOUYIN_WHITE, (int)optional($operator)->id, $operator ? $operator->username : '系统自动处理');
            // 记录日志
            static::addHistory(ShopUnifiedManagementModel::TYPE_DOUYIN_WHITE, $shopIds, $operator);
            return [];
        }
        // 读取excel中的ShopCodes
        $douyinShopCodes = static::importShopCodes($filepath);
        // 只取有效的shopId
        $douyinShops = static::shopCodesToShops($douyinShopCodes, CodeEnum::SHOP_STATUS_NORMAL);
        return collect($douyinShops)->map(function ($item) {
            return collect($item)->only(['id', 'shopCode', 'name'])->toArray();
        })->values()->toArray();
    }

    public static function waimaiRefresh(?User $operator)
    {
        // 黑名单不用刷，只更新白名单
        static::waimaiRefreshWhite($operator);
        // 触发NSQ消息
        static::notify(ShopUnifiedManagementModel::TYPE_WAIMAI_WHITE, (int)optional($operator)->id, $operator ? $operator->username : '系统自动处理');
    }

    public static function waimaiRefreshWhite(?User $operator)
    {
        // 查出所有的黑名单shopIds
        $blackShopIds = ShopUnifiedManagementModel::query()
            ->where('type', ShopUnifiedManagementModel::TYPE_WAIMAI_BLACK)
            ->pluck('shopId')
            ->toArray();
        $whiteShopIds = [];
        // 查出所有的Shop
        Shop::query()
            ->chunkById(1000, function ($shops) use ($blackShopIds, &$whiteShopIds) {
                foreach ($shops as $shop) {
                    if (in_array($shop->id, $blackShopIds)) {
                        // 命中黑名单
                        continue;
                    }
                    // 剩下的都是白名单
                    if ($shop->status !== CodeEnum::SHOP_STATUS_NORMAL) {
                        // 状态不对
                        continue;
                    }
                    $whiteShopIds[$shop->id] = $shop->id;
                }
            });
        static::syncAll($whiteShopIds, $operator, ShopUnifiedManagementModel::TYPE_WAIMAI_WHITE);
    }

    protected static function syncAll(array $shopIds, ?User $operator, int $type)
    {
        $uid         = (int)optional($operator)->id;
        $exists      = ShopUnifiedManagementModel::query()
            ->where('type', $type)
            ->pluck('shopId')
            ->toArray();
        $toInsertIds = array_diff($shopIds, $exists);
        if (count($toInsertIds)) {
            ShopUnifiedManagementModel::insert(collect($toInsertIds)->map(function ($shopId) use ($type, $uid) {
                return [
                    'shopId'       => $shopId,
                    'type'         => $type,
                    'createdByUid' => $uid,
                    'updatedByUid' => $uid,
                    'createdAt'    => time(),
                    'updatedAt'    => time(),
                ];
            })->toArray());
        }
        $toDeleteIds = array_diff($exists, $shopIds);
        if (count($toDeleteIds)) {
            ShopUnifiedManagementModel::whereIn('shopId', $toDeleteIds)
                ->where('type', $type)
                ->update([
                    'updatedByUid' => $uid,
                    'updatedAt'    => time(),
                    'isDeleted'    => 1,
                ]);
        }
        $toUpdateIds = array_intersect($exists, $shopIds);
        if (count($toUpdateIds)) {
            ShopUnifiedManagementModel::whereIn('shopId', $toUpdateIds)
                ->where('type', $type)
                ->update([
                    'updatedByUid' => $uid,
                    'updatedAt'    => time(),
                ]);
        }
    }

    /**
     * shopCode转成shopId
     * @param array $shopCodes
     * @param int|null $status 是否过滤门店状态
     * @return array[]
     */
    public static function shopCodesToShops(array $shopCodes, ?int $status = null): array
    {
        $shopIds = [];
        Shop::query()
            ->chunkById(1000, function ($shops) use ($shopCodes, $status, &$shopIds) {
                foreach ($shops as $shop) {
                    if (null !== $status && $shop->status !== $status) {
                        // 过滤了status且status不相等，则跳过
                        continue;
                    }
                    if (array_key_exists($shop->shopCode, $shopCodes)) {
                        // 命中黑名单
                        $shopIds[$shop->id] = $shop->toArray();
                    }
                }
            });
        return $shopIds;
    }

    protected static function addHistory(int $type, array $shopIds, ?User $operator)
    {
        // 读取现有的内容
        $key            = 'unified_management_history_' . $type;
        $config         = ConfigModel::firstOrNew([
            'type' => 'shop',
            'key'  => $key,
        ]);
        $config->name   = '统管门店编辑记录,类型:' . (ShopUnifiedManagementModel::TYPES[$type] ?? '-');
        $config->remark = '代码维护，不要手动改';
        $list           = (array)json_decode($config->value, true);
        $list[]         = [
            'createdAt' => Carbon::now()->toDateTimeString(),
            'shopCodes' => Shop::query()->whereIn('id', $shopIds)->pluck('shopCode')->toArray(),
            'createdBy' => $operator ? $operator->username : '系统',
        ];
        // 清空旧数据，防止溢出
        while (mb_strlen(json_encode($list, JSON_UNESCAPED_UNICODE)) > 8000) {
            array_shift($list);
            $list = array_values($list);
        }
        $config->value = json_encode($list, JSON_UNESCAPED_UNICODE);
        $config->save();
    }

    public static function waimaiBlack(): array
    {
        return ShopUnifiedManagementModel::query()
            ->with(['shop'])
            ->where('type', ShopUnifiedManagementModel::TYPE_WAIMAI_BLACK)
            ->get()
            ->map(function ($m) {
                return [
                    'id'            => $m->id,
                    'shopId'        => $m->shopId,
                    'shopCode'      => (string)optional($m->shop)->shopCode,
                    'name'          => (string)optional($m->shop)->name,
                    'addressPrefix' => (string)optional($m->shop)->addressPrefix,
                ];
            })->toArray();
    }
}
